package com.lfy.kcat.user.business.impl;
import com.lfy.kcat.user.domain.UserBrowseHistory;
import com.lfy.kcat.user.domain.UserFollows;
import com.lfy.kcat.user.service.UserBrowseHistoryService;
import com.lfy.kcat.user.service.UserFollowsService;
import com.lfy.kcat.user.vo.UserInfoRespVo.UserBaseInfo;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lfy.kcat.user.business.UserAuthBizService;
import com.lfy.kcat.user.business.VerifyCodeBizService;
import com.lfy.kcat.user.domain.Users;
import com.lfy.kcat.user.exception.UserServiceExceptionEnume;
import com.lfy.kcat.user.service.UsersService;
import com.lfy.kcat.user.vo.LoginReqVo;
import com.lfy.kcat.user.vo.LoginRespVo;
import com.lfy.kcat.user.vo.UserInfoRespVo;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author leifengyang
 * @version 1.0
 * @date 2025/9/16 11:24
 * @description:
 */
@Slf4j
@Service
public class UserAuthBizServiceImpl implements UserAuthBizService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    VerifyCodeBizService verifyCodeBizService;

    @Autowired
    UsersService usersService;

    @Autowired
    UserFollowsService  userFollowsService;


    @Autowired
    UserBrowseHistoryService userBrowseHistoryService;


    @Qualifier("appThreadPoolExecutor")
    @Autowired
    ThreadPoolExecutor appThreadPoolExecutor;


    @Override
    public LoginRespVo login(LoginReqVo loginReqVo) {
        //1、去redis比对验证码
        String phone = loginReqVo.getPhone();
        String code = loginReqVo.getCode();

        //2、校验验证码
        boolean verifyCode = verifyCodeBizService.verifyCode(phone, code);

        //3、校验失败，返回失败信息； 抛出业务异常；
        if (!verifyCode) {
            //抛出业务异常
            UserServiceExceptionEnume error = UserServiceExceptionEnume.VERIFY_CODE_ERROR;
            throw new ServiceException(error.getMessage(),
                error.getCode());
        }

        //4、校验成功，登录成功，生成jwt令牌，返回给前端
        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
            .eq(Users::getPhone, phone);
        Users one = usersService.getOne(wrapper);
        if (one == null) {
            //抛出业务异常; 用户不存在；说明第一次登录我们启动，启动注册流程
            //保存数据： 手机号、昵称：游客843787547
            //注册用户；
            one = register(phone);
        }

        //登录成功
        SaLoginParameter parameter = new SaLoginParameter();
        parameter.setExtra("phone", one.getPhone());
        parameter.setExtra("nickname", one.getNickname());

        //5、登录成功，返回jwt令牌
        StpUtil.login(one.getUserId(),parameter);


        //6、获取令牌
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        String tokenName = tokenInfo.getTokenName();
        String tokenValue = tokenInfo.getTokenValue();
        long tokenTimeout = tokenInfo.getTokenTimeout();

        //7、封装数据
        LoginRespVo respVo = new LoginRespVo();
        respVo.setToken(tokenValue);
        respVo.setExpires(String.valueOf(tokenTimeout));


        return respVo;
    }

    /**
     * 返回注册成功
     * @param phone
     * @return
     */
    @Override
    public Users register(String phone) {
        Users users = new Users();
        users.setPhone(phone);
        users.setNickname("游客"+RandomUtil.randomNumbers(8));
        usersService.save(users);
        return users;
    }


    /**
     * 如何打日志：
     * 1. 关键业务处
     * 2. 关键判断处
     *
     * 内容内容：正在做什么，事件标识；  查询用户基本信息， userId = 1;
     * @param userId
     * @return
     */
    @Override
    public UserInfoRespVo getUserInfo(long userId) {
        UserInfoRespVo respVo = new UserInfoRespVo();

        //编排异步任务：需要对异步任务有任意的组合逻辑
        //CompletableFuture: 可完成的未来； 编排异步任务的执行流程
        //Promise: 承诺


        CompletableFuture<Void> baseInfoFuture = CompletableFuture.runAsync(() -> {
            //1、查询用户的基础数据
            Users users = usersService.getById(userId);
            UserBaseInfo userBaseInfo = new UserBaseInfo();
            BeanUtils.copyProperties(users, userBaseInfo);
            //基本数据设置完成
            log.info("获取用户基本信息: 用户id = {}", userId);
            respVo.setBaseInfo(userBaseInfo);
        }, appThreadPoolExecutor);


        CompletableFuture<Void> followFuture = CompletableFuture.runAsync(() -> {
            //2、关注
            long count1 = userFollowsService.count(Wrappers.lambdaQuery(UserFollows.class)
                .eq(UserFollows::getFollowerId, userId));
            respVo.setFollowCount(count1);
        }, appThreadPoolExecutor);


        CompletableFuture<Void> fansFuture = CompletableFuture.runAsync(() -> {
            //3、粉丝
            long count2 = userFollowsService.count(Wrappers.lambdaQuery(UserFollows.class)
                .eq(UserFollows::getFolloweeId, userId));
            respVo.setFansCount(count2);
        }, appThreadPoolExecutor);


        CompletableFuture<Void> followingFuture = CompletableFuture.runAsync(() -> {
            //4、在追
            //TODO 远程获取 播放服务提供的数据
            respVo.setFollowingCount(0L);
        },appThreadPoolExecutor);


        CompletableFuture<Void> historyFuture = CompletableFuture.runAsync(() -> {
            //5、观看历史
            long count4 = userBrowseHistoryService.count(Wrappers.lambdaQuery(UserBrowseHistory.class)
                .eq(UserBrowseHistory::getUserId, userId));
            respVo.setHistoryCount(count4);
        }, appThreadPoolExecutor);


        //所有任务执行完才能
        CompletableFuture.allOf(baseInfoFuture,
            followFuture,
            fansFuture,
            followingFuture,
            historyFuture).join();

        return respVo;
    }
}
